package com.jprocms.module.cms.controller.portal.api;

import cn.hutool.core.collection.CollUtil;
import com.jpro.framework.common.pojo.CommonResult;
import com.jpro.framework.common.pojo.PageResult;
import com.jpro.framework.common.util.string.StrUtils;
import com.jprocms.module.cms.convert.content.ContentConvert;
import com.jprocms.module.cms.dal.dataobject.channel.ChannelDO;
import com.jprocms.module.cms.dal.dataobject.content.ContentDO;
import com.jprocms.module.cms.dal.mysql.content.ContentMapper;
import com.jprocms.module.cms.es.dto.EsFrontSearchDto;
import com.jprocms.module.cms.es.dto.FrontSearchDto;
import com.jprocms.module.cms.es.service.ContentEsService;
import com.jprocms.module.cms.es.vo.EsChannelContentCountVO;
import com.jprocms.module.cms.es.vo.EsContentVO;
import com.jprocms.module.cms.framework.tree.TreePathUtil;
import com.jprocms.module.cms.service.channel.ChannelService;
import com.jprocms.module.cms.service.content.ContentService;
import com.jprocms.module.cms.service.sysword.SysWordService;
import com.jprocms.module.cms.util.CmsContextUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.jpro.framework.common.pojo.CommonResult.success;
import static com.jprocms.module.cms.constant.CmsSysConstants.FRONT_API;

/**
 * @author jprocms
 */

@Tag(name = "前台 - 内容检索")
@RestController
@RequestMapping(FRONT_API + "/content")
public class ContentSearchController {

    @Resource
    private ContentEsService esContentService;
    @Autowired
    private ChannelService channelService;
    @Resource
    private ContentService contentService;
    @Resource
    private ContentMapper contentMapper;
    @Resource
    private SysWordService sysWordService;

    @GetMapping(value = "search/page")
    @Operation(summary = "内容搜索接口")
    public CommonResult<PageResult<EsContentVO>> search(@ModelAttribute FrontSearchDto queryDto)
            throws Exception {
        Long currSiteId = CmsContextUtil.getCurrSiteId();
        if (queryDto.getSiteId() == null) {
            queryDto.setSiteId(currSiteId);
        }
        if (queryDto.getPageSize() == null) {
            queryDto.setPageSize(10L);
        }
        if (queryDto.getPageNo() == null) {
            queryDto.setPageNo(1L);
        }
        EsFrontSearchDto searchDto = ContentConvert.INSTANCE.convert2EsQuertDto(queryDto);
        //栏目id和栏目路径一起合并参数
        if (StringUtils.isNotBlank(queryDto.getChannelIdStrs())
                || StringUtils.isNotBlank(queryDto.getChannelPaths())) {
            List<Long> channelIds = combinChannelIds(queryDto.getChannelIdStrs(), queryDto.getChannelPaths(), queryDto.getSiteId());
            searchDto.setChannelIds(channelIds);
        }
        //默认当前站点
        searchDto.setSiteId(currSiteId);
        if (queryDto.getSiteId() != null) {
            searchDto.setSiteId(queryDto.getSiteId());
        }
        PageResult<EsContentVO> resultDto = esContentService.getContentPageForFront(searchDto);
        if (resultDto == null) {
            return success(resultDto);
        }
        //暂时不做栏目数量统计
//        List<EsChannelContentCountVO> channelContentCountVOs = resultDto.getChannelContentCount();
//        if (CollectionUtils.isNotEmpty(channelContentCountVOs)) {
//            Map<Long, EsChannelContentCountVO> channelMap = new HashMap<>();
//            CollUtil.toMap(channelContentCountVOs,channelMap,EsChannelContentCountVO::getChannelId,item->item);
//            List<Long> channelIds = Lists.newArrayList(channelMap.keySet());
//            List<ChannelDO> channels = channelService.getChannelList(channelIds);
//            CollUtil.toMap(channels, channelIdNameMap,ChannelDO::getId,ChannelDO::getName);
//            //栏目统计结果
//            resultDto.setChannelContentCount(mergeChannelContentCount(channelMap, channels));
//        }
        //搜索词统计入库
        if (CollectionUtils.isNotEmpty(searchDto.getKeyWords())) {
            sysWordService.addSearchCount(searchDto.getKeyWords(), 1L, currSiteId);
        }
        return success(resultDto);
    }

    /**
     * 栏目的内容数统计合并到顶层栏目
     *
     * @param channelMap 栏目名和es content count Map
     * @param channels
     * @return
     */
    private List<EsChannelContentCountVO> mergeChannelContentCount(Map<Long, EsChannelContentCountVO> channelMap, List<ChannelDO> channels) {
        if (MapUtils.isEmpty(channelMap) || CollectionUtils.isEmpty(channels)) {
            return Collections.emptyList();
        }
        Map<Long, ChannelDO> idMap = new HashMap<>();
        CollUtil.toMap(channels, idMap, ChannelDO::getId, item -> item);
        Map<Long, List<EsChannelContentCountVO>> topChannelEsContentCountMap = channelMap.entrySet().stream()
                .filter(en -> idMap.containsKey(en.getKey())).collect(
                        Collectors.groupingBy(en -> getTopId(idMap.get(en.getKey())),
                                Collectors.mapping(en -> en.getValue(), Collectors.toList())));
        List<ChannelDO> channelList = channelService.getChannelList(topChannelEsContentCountMap.keySet());
        Map<Long, String> channelIdNameMap = new HashMap<>();
        CollUtil.toMap(channelList, channelIdNameMap, ChannelDO::getId, ChannelDO::getName);
        List<EsChannelContentCountVO> topChannelContentCountVOS = topChannelEsContentCountMap.entrySet().stream().map(tc -> {
            Long channelId = tc.getKey();
            EsChannelContentCountVO channelContentCountVO = new EsChannelContentCountVO();
            channelContentCountVO.setChannelId(channelId);
            channelContentCountVO.setChannelName(channelIdNameMap.get(channelId));
            channelContentCountVO.setContentCount(tc.getValue().stream().mapToLong(EsChannelContentCountVO::getContentCount).sum());
            return channelContentCountVO;
        }).collect(Collectors.toList());
        return topChannelContentCountVOS;
    }

    private Long getTopId(ChannelDO channel) {
        Long topId = TreePathUtil.getTopId(channel.getPath());
        return topId == null ? channel.getId() : topId;
    }

    private void fillChannelNameAndUrls(List<EsContentVO> records, Map<Long, String> channelIdNameMap) {
        if (CollectionUtils.isEmpty(records)) {
            return;
        }
        List<Long> ids = com.jpro.framework.common.util.collection.CollectionUtils.convertList(records, EsContentVO::getId);
        List<ContentDO> contentList = contentService.getContentList(ids, null);
        Map<Long, String> contentUrlMap = com.jpro.framework.common.util.collection.CollectionUtils.convertMap(contentList, ContentDO::getId, ContentDO::getUrl);
        Map<Long, String> contentDyUrlMap = com.jpro.framework.common.util.collection.CollectionUtils.convertMap(contentList, ContentDO::getId, ContentDO::getDynamicUrl);
        records.forEach(r -> {
            r.setUrl(contentUrlMap.get(r.getId()));
            r.setDynamicUrl(contentDyUrlMap.get((r.getId())));
            r.setChannelName(channelIdNameMap.get(r.getChannelId()));
        });
    }

    /**
     * 合并栏目id和栏目路径为栏目id  查询所有叶子节点栏目 集合
     *
     * @param channelIdStr
     * @param channelPaths
     * @return
     */
    private List<Long> combinChannelIds(String channelIdStr, String channelPaths, Long siteId) {
        List<Long> channelIds = new ArrayList<>();
        if (StringUtils.isNotBlank(channelIdStr)) {
            channelIds.addAll(StrUtils.splitToLong(channelIdStr));
        }
        if (StringUtils.isNotBlank(channelPaths)) {
            channelIds.addAll(findChannelIdsByPath(channelPaths, siteId));
        }
        if (CollectionUtils.isEmpty(channelIds)) {
            return channelIds;
        }
        return com.jpro.framework.common.util.collection.CollectionUtils.convertList(channelService.selectLeafChannels(channelIds), ChannelDO::getId);
    }

    /**
     * 查询栏id 根据栏目路径
     *
     * @param channelPaths 栏目路径
     * @return
     */
    private List<Long> findChannelIdsByPath(String channelPaths, Long siteId) {
        List<String> paths = StrUtils.splitToString(channelPaths);
        List<ChannelDO> channels = channelService.selectByChannelPath(paths, siteId);
        return com.jpro.framework.common.util.collection.CollectionUtils.convertList(channels, ChannelDO::getId);
    }

}
